Announcing the AWS Amplify CLI toolchain. Click here to read more.

Storage

AWS Amplify Storage module provides a simple mechanism for managing user content for your app in public, protected or private storage buckets.

Ensure you have installed and configured the Amplify CLI and library.

Automated Setup

AWS Mobile CLI helps you to create and configure the storage buckets for your app. The default implementation of the Storage module leverages Amazon S3.

Create Your Backend with the CLI

To create a project fully functioning with the Storage category, run the following command:

$ amplify add storage

and select Content in prompted options:

? Please select from one of the below mentioned services (Use arrow keys)
❯ Content (Images, audio, video, etc.)
  NoSQL Database

The CLI will walk you though the options to enable Auth, if not enabled previously, and name your S3 bucket. To update your backend run:

$ amplify push

When your backend is successfully updated, your new configuration file aws-exports.js is copied under your source directory, e.g. ‘/src’.

Configure Your App

In your app’s entry point i.e. App.js, import and load the configuration file aws-exports.js which has been created and replaced into /src folder in the previous step.

import Amplify, { Storage } from 'aws-amplify';
import aws_exports from './aws-exports';
Amplify.configure(aws_exports);

Manual Setup

Manual setup enables you to use your existing Amazon Cognito and Amazon S3 credentials in your app:

import Amplify from 'aws-amplify';

Amplify.configure({
    Auth: {
        identityPoolId: 'XX-XXXX-X:XXXXXXXX-XXXX-1234-abcd-1234567890ab', //REQUIRED - Amazon Cognito Identity Pool ID
        region: 'XX-XXXX-X', // REQUIRED - Amazon Cognito Region
        userPoolId: 'XX-XXXX-X_abcd1234', //OPTIONAL - Amazon Cognito User Pool ID
        userPoolWebClientId: 'XX-XXXX-X_abcd1234', //OPTIONAL - Amazon Cognito Web Client ID
    },
    Storage: {
        bucket: '', //REQUIRED -  Amazon S3 bucket
        region: 'XX-XXXX-X', //OPTIONAL -  Amazon service region
    }
});

Setup Amazon S3 Bucket CORS Policy

To make calls to your S3 bucket from your App, you need to setup CORS Policy for your S3 bucket.

Following steps will enable your CORS Policy:

  1. Go to Amazon S3 Console and click on your project’s userfiles bucket, which is normally named as [Project Name]-userfiles-mobilehub-[App Id].
  2. Click on the Permissions tab for your bucket, and then click on CORS configuration tile.
  3. Update your bucket’s CORS Policy to look like:
<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
    <AllowedOrigin>*</AllowedOrigin>
    <AllowedMethod>HEAD</AllowedMethod>
    <AllowedMethod>GET</AllowedMethod>
    <AllowedMethod>PUT</AllowedMethod>
    <AllowedMethod>POST</AllowedMethod>
    <AllowedMethod>DELETE</AllowedMethod>
    <MaxAgeSeconds>3000</MaxAgeSeconds>
    <ExposeHeader>x-amz-server-side-encryption</ExposeHeader>
    <ExposeHeader>x-amz-request-id</ExposeHeader>
    <ExposeHeader>x-amz-id-2</ExposeHeader>
    <AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>

Note: You can restrict the access to your bucket by updating AllowedOrigin to include individual domains.

File Access Levels

Storage module can manage files with three different access levels; public, protected and private.

Files with public access level can be accessed by all users who are using your app. In S3, they are stored under the public/ path in your S3 bucket.

Files with protected access level are readable by all users but writable only by the creating user. In S3, they are stored under protected/{user_identity_id}/ where the user_identity_id corresponds to a unique Amazon Cognito Identity ID for that user.

Files with private access level are only accessible for specific authenticated users only. In S3, they are stored under private/{user_identity_id}/ where the user_identity_id corresponds to a unique Amazon Cognito Identity ID for that user.

The access level can be configured on the Storage object globally. Alternatively, the access levels can be set in individual function calls.

Default access level for Storage module is public. Unless you configure Storage otherwise, all uploaded files will be publicly available for all users.

Access level configuration on the Storage object:

Storage.configure({ level: 'private' });

Storage.get('welcome.png'); // Gets the welcome.png belongs to current user

Configuration when calling the API:

Storage.get('welcome.png', { level: 'public' }); // Gets welcome.png in public space

The default access level is public:

Storage.get('welcome.png'); // Get welcome.png in public space

There is also a shortcut vault, which is merely a Storage instance with private level set:

Storage.vault.get('welcome.png'); // Get the welcome.png belonging to current user

Working with the API

Import Storage from the aws-amplify library:

import { Storage } from 'aws-amplify';

If you use aws-exports.js file, Storage is already configured. To configure Storage manually,

Storage.configure({
    bucket: //Your bucket ARN;
    region: //Specify the region your bucket was created in;
    identityPoolId: //Specify your identityPoolId for Auth and Unauth access to your bucket;
});

Put

Puts data into Amazon S3.

Public level:

Storage.put('test.txt', 'Hello')
    .then (result => console.log(result))
    .catch(err => console.log(err));

Protected level:

Storage.put('test.txt', 'Protected Content', {
    level: 'protected',
    contentType: 'text/plain'
})
.then (result => console.log(result))
.catch(err => console.log(err));

Private level:

Storage.put('test.txt', 'Private Content', {
    level: 'private',
    contentType: 'text/plain'
})
.then (result => console.log(result))
.catch(err => console.log(err));

Upload an image in the browser:

class S3ImageUpload extends React.Component {
  onChange(e) {
      const file = e.target.files[0];
      Storage.put('example.png', file, {
          contentType: 'image/png'
      })
      .then (result => console.log(result))
      .catch(err => console.log(err));
  }

  render() {
      return (
          <input
              type="file" accept='image/png'
              onChange={(e) => this.onChange(e)}
          />
      )
  }
}

Upload an image in React Native app:

import RNFetchBlob from 'react-native-fetch-blob';

readFile(filePath) {
    return RNFetchBlob.fs.readFile(filePath, 'base64').then(data => new Buffer(data, 'base64'));
}

readFile(imagePath).then(buffer => {
    Storage.put(key, buffer, {
        contentType: imageType
    })
}).catch(e => {
    console.log(e);
});

When a networking error happens during the upload, Storage module retries upload for a maximum of 4 attempts. If the upload fails after all retries, you will get an error.

Get

Retrieves a publicly accessible URL for data stored.

Public level:

Storage.get('test.txt')
    .then(result => console.log(result))
    .catch(err => console.log(err));

Protected level: To get current user’s objects

Storage.get('test.txt', { level: 'protected' })
    .then(result => console.log(result))
    .catch(err => console.log(err));

To get other users’ objects

Storage.get('test.txt', { 
    level: 'protected', 
    identityId: 'xxxxxxx' // the identityId of that user
})
.then(result => console.log(result))
.catch(err => console.log(err));

Private level:

Storage.get('test.txt', {level: 'private'})
    .then(result => console.log(result))
    .catch(err => console.log(err));

You can use expires option to limit the availability of your URLs. This configuration returns the pre-signed URL that expires in 60 seconds:

Storage.get('test.txt', {expires: 60})
    .then(result => console.log(result))
    .catch(err => console.log(err));

Remove

Delete stored data from the storage bucket.

Public level:

Storage.remove('test.txt')
    .then(result => console.log(result))
    .catch(err => console.log(err));

Protected level:

Storage.remove('test.txt', {level: 'protected'})
    .then(result => console.log(result))
    .catch(err => console.log(err));

Private level:

Storage.remove('test.txt', {level: 'private'})
    .then(result => console.log(result))
    .catch(err => console.log(err));

List

List keys under path specified.

Public level:

Storage.list('photos/')
    .then(result => console.log(result))
    .catch(err => console.log(err));

Protected level: To list current user’s objects

Storage.list('photos/', { level: 'protected' })
    .then(result => console.log(result))
    .catch(err => console.log(err));

To get other users’ objects

Storage.list('photos/', { 
    level: 'protected', 
    identityId: 'xxxxxxx' // the identityId of that user
})
.then(result => console.log(result))
.catch(err => console.log(err));

Private level:

Storage.list('photos/', {level: 'private'})
    .then(result => console.log(result))
    .catch(err => console.log(err));

API Reference

For the complete API documentation for Storage module, visit our API Reference

Tracking Events

You can enable automatic tracking of storage events such as uploads and downloads, by setting { track: true } when calling the Storage API.

(Note: this option is currently only supported in aws-amplify). Enabling this will automatically send Storage events to Amazon Pinpoint and you will be able to see them within the AWS Pinpoint console under Custom Events. The event name will be ‘Storage’ and in Event Attributes, you can see details about the event, e.g. Storage > Method > Put.

Track all the Storage events:

Storage.configure({ track: true })

Track a specific storage action:

Storage.get('welcome.png', { track: true });

You can also use the track property directly on React components.

UI Components for React

aws-amplify-react package provides React UI components for common usecases such as picking a file and image previews.

Picker

Picker is used to pick a file from local device storage. PhotoPicker and TextPicker components are specific to image and text file types .

Listen to PhotoPicker onPick event:

import { PhotoPicker } from 'aws-amplify-react';

render() {
    <PhotoPicker onPick={data => console.log(data)} />
}

To display a preview, you can use preview directive:

<PhotoPicker preview onLoad={dataURL => console.log(dataURL)} />

You can retrieve the URL of the image by implementing onLoad action. In this case, you may also want to hide the preview:

<PhotoPicker preview="hidden" onLoad={dataURL => console.log(dataURL)} />

S3Image

S3Image component renders an Amazon S3 object key as an image:

import { S3Image } from 'aws-amplify-react';

render() {
    return <S3Image imgKey={key} />
}

For private images, supply the level property:

return <S3Image level="private" imgKey={key} />

To initiate an upload, set the body property:

import { S3Image } from 'aws-amplify-react';

render() {
    return <S3Image imgKey={key} body={this.state.image_body} />
}

To hide the image shown in the S3Image, set hidden:

import { S3Image } from 'aws-amplify-react';

render() {
    return <S3Image hidden imgKey={key} />
}

Image URL

S3Image converts path to actual URL. To get the URL, listen to the onLoad event:

<S3Image imgKey={key} onLoad={url => console.log(url)} />

Photo Picker

Set picker property to true on S3Image. A PhotoPicker let the user pick a picture from the device. After users picks an image, the image will be uploaded with imgKey.

<S3Image imgKey={key} picker />

When you set path, the key for the image will be the combination of path and image file name.

<S3Image path={path} picker />

To generate a custom key value, you can provide a callback:

function fileToKey(data) {
    const { name, size, type } = data;
    return 'test_' + name;
}

...
<S3Image path={path} picker fileToKey={fileToKey} />

S3Image will escape all spaces in key values to underscore. For example, ‘a b’ will ve converted to ‘a_b’.

S3Text

S3Text is similar to S3Image. The only difference is S3Text is used for text content.

S3Album

S3Album renders a list of S3Image and S3Text objects:

import { S3Album } from 'aws-amplify-react';

render() {
    return <S3Album path={path} />

For display private objects, supply the level property:

return <S3Album level="private" path={path} />

You can use filter property customize the path for your album:

return (
    <S3Album
        level="private"
        path={path}
        filter={(item) => /jpg/i.test(item.path)}
    />
);

Picker

Set picker property to true on S3Album. A Picker let user select photos or text files from the device. The selected files will be automatically uploaded to the path.

<S3Album path={path} picker />

By default, photo picker saves images on S3 with filename as the key. To have custom keys, you can provide a callback:

function fileToKey(data) {
    const { name, size, type } = data;
    return 'test_' + name;
}

...
    <S3Album path={path} picker fileToKey={fileToKey} />

S3Album will escape all spaces in key value to underscore. For example, ‘a b’ will be converted to ‘a_b’.

Tracking Events for UI Components

You can automatically track Storage operations on the following React components: S3Album, S3Text, S3Image by providing a track prop:

return <S3Album track />

Enabling tracking will automatically send ‘Storage’ events to Amazon Pinpoint, and you will be able to see the results in AWS Pinpoint console under Custom Events. The event name will be Storage, and event details will be displayed in attributes , e.g. Storage -> Method -> Put.

UI Components for Angular

aws-amplify-angular provides similar storage ui components.

Photo Picker

Add a photo picker to your components template:


<amplify-photo-picker 
    (loaded)="onImagePreviewLoaded($event)"
    (picked)="onImageSelected($event)">
</amplify-photo-picker>

S3 Album

Add an S3 album component to your template:


<amplify-s3-album 
    path=""
    (selected)="onAlbumImageSelected($event)">  			
</amplify-s3-album>

See the Angular Guide for usage.

Customization

Customize Upload Path

You can customize your upload path by defining prefixes:

const customPrefix: {
    public: 'myPublicPrefix/',
    protected: 'myProtectedPrefix/',
    private: 'myPrivatePrefix/'
};

Storage.put('test.txt', 'Hello', {
    customPrefix: customPrefix,
    // ...
})
.then (result => console.log(result))
.catch(err => console.log(err));

For example, if you want to enable read, write and delete operation for all the objects under path myPublicPrefix/, declare it in your IAM policy:

"Statement": [
    {
        "Effect": "Allow",
        "Action": [
            "s3:GetObject",
            "s3:PutObject",
            "s3:DeleteObject"
        ],
        "Resource": [
            "arn:aws:s3:::your-s3-bucket/myPublicPrefix/*",
        ]
    }
]

If you want to have custom private path prefix like myPrivatePrefix/, you need to add it into your IAM policy:

"Statement": [
    {
        "Effect": "Allow",
        "Action": [
            "s3:GetObject",
            "s3:PutObject",
            "s3:DeleteObject"
        ],
        "Resource": [
            "arn:aws:s3:::your-s3-bucket/myPrivatePrefix/${cognito-identity.amazonaws.com:sub}/*"
        ]
    }
]

This ensures only the authenticated users has the access to the objects under the path.

Using Modular Imports

If you only need to use Storage, you can do: npm install @aws-amplify/storage which will only install the Storage module for you. Note: if you’re using Cognito Federated Identity Pool to get AWS credentials, please also install @aws-amplify/auth.

Then in your code, you can import the Storage module by:

import Storage from '@aws-amplify/storage';

Storage.configure();